package com.nes.rom;

import com.nes.processor.AluUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author sad
 */
public class RomReader {

    public Rom createRom(File file) {
        try {
            Rom rom = new Rom();
            BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));
            stream.mark((int)file.length());
            byte[] magicNumber = new byte[4];
            stream.read(magicNumber);
            AluUtils.assertBytesEquals(magicNumber, new byte[]{0x4e, 0x45, 0x53, 0x1A});
            int mapper=0;
            int prgRomBankCount=AluUtils.unsignedByte((byte) stream.read());
            int prgRomSize = prgRomBankCount * 16384;
            int vRomBankCount=AluUtils.unsignedByte((byte) stream.read());
            int VRomSize =  vRomBankCount* 8192;
            int flags = stream.read();
            int mirroringMode = flags & 0x01;
            int hasBatteryBackedRam = (flags >> 1) & 0x01;
            int hasTrainer = (flags >> 2) & 0x01;
            int hasFourScreenVram = (flags >> 3) & 0x01;
            int lowBitsMapperType = (flags >> 4) & 0x07;
            mapper=lowBitsMapperType;

            flags = stream.read();
            int isVsSystemCartridge = flags & 0x01;
            int highBitsMapperType = (flags >> 4) & 0x07;
            mapper=mapper|highBitsMapperType<<4;

            int prgRamSizeInBytes = AluUtils.unsignedByte((byte) stream.read());
            if (prgRamSizeInBytes == 0) {
                prgRamSizeInBytes = 1;
            }

            flags = stream.read();
            int palOrNtsc = flags & 0x01;
            
            stream.reset();
            stream.skip(16);
            byte[] prgRomBanks = new byte[prgRomSize];
            byte[] vromBanks = new byte[VRomSize];
            stream.read(prgRomBanks);
            stream.read(vromBanks);
            stream.close();
            rom.setMapper(mapper);
            rom.setPrgRomBankCount(prgRomBankCount);
            rom.setVRomBankCount(vRomBankCount);
            rom.setPrgRomSize(prgRomSize);
            rom.setVromSize(VRomSize);
            rom.setMirroringMode(mirroringMode);
            rom.setBattery_backed_ram(hasBatteryBackedRam);
            rom.setHasTrainer(hasTrainer);
            rom.setHasFourScreenVram(hasFourScreenVram);
            rom.setPrgRamSize(prgRamSizeInBytes);
            rom.setPalOrNtsc(palOrNtsc);
            rom.setRomBanks(prgRomBanks);
            rom.setVromBanks(vromBanks);
            return rom;
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}
